package com.huawei.cloud.phone.management.infrastructure.pkg;

import com.huawei.cloud.phone.management.domain.pkg.ObsFileData;
import com.huawei.cloud.phone.management.domain.pkg.PkgData;
import com.huawei.cloud.phone.management.domain.pkg.PkgGateway;
import com.huawei.cloud.phone.management.domain.pkg.PkgResult;
import com.huawei.cloud.phone.management.infrastructure.ClientFactory;
import com.huawei.cloud.phone.management.infrastructure.CphClientInvoker;
import com.huaweicloud.sdk.cph.v1.CphClient;
import com.huaweicloud.sdk.cph.v1.model.*;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Component
@Slf4j
public class PkgGatewayImpl implements PkgGateway {
    @Override
    public Optional<String> pushFile(List<ObsFileData> data) {
        log.info("start push apk {}", data);
        try (ObsClient obsClient = ClientFactory.getObsClient()) {
            for (ObsFileData fileData : data) {
                obsClient.putObject(fileData.getBucketName(), fileData.getObjectPath(), fileData.getInputStream());
            }
            return Optional.empty();
        } catch (ObsException e) {
            log.error("operation obs failed", e);
            return Optional.of(e.getErrorMessage());
        } catch (IOException e) {
            log.error("close obs failed", e);
            return Optional.of(e.getMessage());
        }
    }

    @Override
    public List<PkgResult> installApk(List<String> phoneIds, List<ObsFileData> data) {
        log.info("start install apk {}", data);
        StringBuilder contentBuilder = new StringBuilder("-t -r");
        for (ObsFileData fileData : data) {
            contentBuilder.append(" obs://").append(fileData.getBucketName()).append("/").append(fileData.getObjectPath());
        }
        RunShellCommandRequest request = new RunShellCommandRequest()
                .withBody(new RunShellCommandRequestBody()
                        .withCommand(data.size() == 1 ? "install" : "install-multiple")
                        .withContent(contentBuilder.toString())
                        .withPhoneIds(phoneIds));

        CphClientInvoker<RunShellCommandRequest, RunShellCommandResponse> invoker = new CphClientInvoker<>();
        return invoker.invoke(request, CphClient::runShellCommand);
    }

    @Override
    public List<PkgResult> uninstallApk(List<String> phoneIds, String pkgName) {
        log.info("start uninstall apk {}", pkgName);
        RunShellCommandRequest request = new RunShellCommandRequest().withBody(new RunShellCommandRequestBody()
                .withCommand("shell").withContent(String.format("pm uninstall %s", pkgName))
                .withPhoneIds(phoneIds));

        CphClientInvoker<RunShellCommandRequest, RunShellCommandResponse> invoker = new CphClientInvoker<>();
        return invoker.invoke(request, CphClient::runShellCommand);
    }

    @Override
    public List<PkgResult> uninstallTar(List<String> phoneIds, String pkgName) {
        log.info("start uninstall tar {}", pkgName);
        RunShellCommandRequest request = new RunShellCommandRequest().withBody(new RunShellCommandRequestBody()
                .withCommand("shell").withContent(String.format("appctrl uninstall %s", pkgName))
                .withPhoneIds(phoneIds));

        CphClientInvoker<RunShellCommandRequest, RunShellCommandResponse> invoker = new CphClientInvoker<>();
        return invoker.invoke(request, CphClient::runShellCommand);
    }

    @Override
    public Optional<PkgResult> prepareTar(String phoneId, PkgData.TarData data) {
        log.info("start prepare tar {}", data);
        String pkgName = data.getPkgName();
        StorageInfo info = new StorageInfo().withBucketName(data.getBucketName())
                .withObjectPath(data.getTarObjectPath())
                .withPhoneId(phoneId)
                .withIncludeFiles(Arrays.asList("/data/app/" + pkgName + "-*", "/data/data/" + pkgName, "/data/media/0/Android/data/" + pkgName));
        BatchExportCloudPhoneDataRequest request = new BatchExportCloudPhoneDataRequest()
                .withBody(new BatchExportCloudPhoneDataRequestBody()
                        .withStorageInfos(Collections.singletonList(info)));

        CphClientInvoker<BatchExportCloudPhoneDataRequest, BatchExportCloudPhoneDataResponse> invoker = new CphClientInvoker<>();
        List<PkgResult> result = invoker.invoke(request, CphClient::batchExportCloudPhoneData);
        return result.isEmpty() ? Optional.empty() : Optional.of(result.get(0));
    }

    @Override
    public List<PkgResult> pushShareTar(List<String> serverIds, PkgData.TarData data) {
        log.info("start push share tar {}", data);
        PushShareAppsRequest request = new PushShareAppsRequest().withBody(new PushShareAppsRequestBody()
                .withPreInstallApp(0).withPackageName(data.getPkgName()).withBucketName(data.getBucketName())
                .withObjectPath(data.getTarObjectPath()).withServerIds(serverIds));

        CphClientInvoker<PushShareAppsRequest, PushShareAppsResponse> invoker = new CphClientInvoker<>();
        return invoker.invoke(request, CphClient::pushShareApps);
    }

    @Override
    public List<PkgResult> installTar(List<String> phoneIds, String pkgName) {
        log.info("start install tar {}", pkgName);
        RunShellCommandRequest request = new RunShellCommandRequest().withBody(new RunShellCommandRequestBody()
                .withCommand("shell").withContent(String.format("appctrl install %s", pkgName))
                .withPhoneIds(phoneIds));

        CphClientInvoker<RunShellCommandRequest, RunShellCommandResponse> invoker = new CphClientInvoker<>();
        return invoker.invoke(request, CphClient::runShellCommand);
    }
}
